Fork me on GitHub

380. Insert Delete GetRandom O(1)

\380. Insert Delete GetRandom O(1)

Medium

1501109Share

Design a data structure that supports all following operations in average O(1) time.

  1. insert(val): Inserts an item val to the set if not already present.
  2. remove(val): Removes an item val from the set if present.
  3. getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Init an empty set.
RandomizedSet randomSet = new RandomizedSet();

// Inserts 1 to the set. Returns true as 1 was inserted successfully.
randomSet.insert(1);

// Returns false as 2 does not exist in the set.
randomSet.remove(2);

// Inserts 2 to the set, returns true. Set now contains [1,2].
randomSet.insert(2);

// getRandom should return either 1 or 2 randomly.
randomSet.getRandom();

// Removes 1 from the set, returns true. Set now contains [2].
randomSet.remove(1);

// 2 was already in the set, so return false.
randomSet.insert(2);

// Since 2 is the only number in the set, getRandom always return 2.
randomSet.getRandom();

python list,set,dictionary时间复杂度参考。这题重点在于如何实现O(1)的时间,因为在python list 里,remove 和 insert 都是O(n)的时间复杂度。题目要求 insert 和 remove 能够判断 val 在不在里面,list 的 in 也是O(n)。 所以我们就想到了用hash map,或者说是set。

然后我就想到下面的代码,但是虽然满足了remove, add, in都是O(1),但是缺不能满足getRandom(self),因为list()需要的时间是O(n).

错误示范:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import random
class RandomizedSet:
def __init__(self):
"""
Initialize your data structure here.
"""
self.mem = set()

def insert(self, val: int) -> bool:
"""
Inserts a value to the set. Returns true if the set did not already contain the specified element.
"""
if val in self.mem:
return False
else:
self.mem.add(val)
return True

def remove(self, val: int) -> bool:
"""
Removes a value from the set. Returns true if the set contained the specified element.
"""
if val not in self.mem:
return False
else:
self.mem.remove(val)
return True

def getRandom(self) -> int:
"""
Get a random element from the set.
"""
self.List = list(self.mem) # attention: the time complexity is O(n)
return (random.choice(self.List))

所以,思来想去还是需要一个list来存储val。但是remove如何在O(1)时间删除list里的东西又成了问题。这时候就参考了这个方法,简而言之,记录每一个val在list里的位置,然后将此位置上的val替换成末尾的数,再在dict里更新末位数位置(当前val的位置)把末尾的数pop出去就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import random
class RandomizedSet:
def __init__(self):
"""
Initialize your data structure here.
"""
self.listMem = []
self.dicMem = {}

def insert(self, val: int) -> bool:
"""
Inserts a value to the set. Returns true if the set did not already contain the specified element.
"""
if val not in self.dicMem:
self.listMem.append(val)
self.dicMem[val] = len(self.listMem) - 1
return True
else:
return False

def remove(self, val: int) -> bool:
"""
Removes a value from the set. Returns true if the set contained the specified element.
"""
if val in self.dicMem:
pos, last = self.dicMem[val], self.listMem[-1]
self.dicMem[last], self.listMem[pos] = pos, last
del self.dicMem[val]; self.listMem.pop()
return True
else:
return False

def getRandom(self) -> int:
"""
Get a random element from the set.
"""
return random.choice(self.listMem)
Shuolin Tian wechat
欢迎加我微信交流